/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author        Notes
 */

#include <rtthread.h>

#include "drv_gpio.h"
#include "drv_beep.h"

#define DBG_TAG "drv.beep"
#include <drv_log.h>

static struct drv_beep_device _beep;
static rt_timer_t timer = RT_NULL;
struct beep_state _state;

void beep_pin_init(void)
{
    rt_pin_mode(GET_PIN(B, 5), PIN_MODE_OUTPUT);
}

static void timeout(void *parameter)
{
    static uint8_t state = 0;

    if (_state.time > 0)
    {
        if (_state.time > (1000 / _state.hz))
        {
            _state.time -= (1000 / _state.hz);
        }
        else  
        {
            _state.time = 0;
            rt_timer_stop(timer);
        }
    }
    else if (_state.time == BEEP_TIME_FOREVER) // 长响
    {
        
    }
    else if (_state.time == 0) // 终止
    {
        rt_timer_stop(timer);
    }
    else 
    {
        return;
    }

    if (state == 0)
    {
        state = 1;
        rt_pin_write(GET_PIN(B, 5), PIN_HIGH);
    }
    else 
    {
        state = 0;
        rt_pin_write(GET_PIN(B, 5), PIN_LOW);
    }
    
}

//////////////////////////////////////////////////////////////////////////////////////////////////
static rt_err_t drv_beep_init(rt_device_t dev)
{
    beep_pin_init();

    return RT_EOK;
}

static rt_err_t drv_beep_open(rt_device_t dev, rt_uint16_t oflag)
{
    timer = rt_timer_create("beep", timeout, RT_NULL, 1, RT_TIMER_FLAG_PERIODIC);
    if (timer == RT_NULL)
    {
        return RT_ERROR;
    }

    return RT_EOK;
}

static rt_err_t drv_beep_close(rt_device_t dev)
{
    rt_err_t result = RT_EOK;

    if (timer == RT_NULL)
    {
        return RT_ERROR;
    }

    result = rt_timer_delete(timer);
    if (result != RT_EOK)
    {
        return result;
    }
    timer = RT_NULL;

    return RT_EOK;
}

static rt_size_t drv_beep_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
    RT_ASSERT(dev);
    RT_ASSERT(size <= sizeof(struct beep_state));

    struct beep_state state = *(struct beep_state *)buffer;
    rt_tick_t t_cycle = 0;

    if (state.hz != 0)
    {
        t_cycle = 1000 / state.hz;
        rt_timer_control(timer, RT_TIMER_CTRL_SET_TIME, &t_cycle);
    }
    else 
    {
        return 0;
    }

    _state = state;

    if (state.on == 1)
    {
        rt_timer_start(timer);
    }
    else 
    {
        rt_timer_stop(timer);
    }

    return sizeof(struct beep_state);
}

static rt_err_t drv_beep_control(rt_device_t dev, int cmd, void *args)
{
    struct drv_beep_device *beep = (struct drv_beep_device *)dev;

    switch (cmd)
    {
    case 0:
    {
        
    }
    break;
    }

    return RT_EOK;
}

#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops beep_ops = {
    drv_beep_init,
    drv_beep_open,
    drv_beep_close,
    RT_NULL,
    drv_beep_write,
    drv_beep_control
};
#endif

int drv_beep_hw_init(void)
{
    rt_err_t result = RT_EOK;
    struct rt_device *device = &_beep.parent;

    /* memset _beep to zero */
    rt_memset(&_beep, 0x00, sizeof(_beep));

    device->type = RT_Device_Class_Miscellaneous;
#ifdef RT_USING_DEVICE_OPS
    device->ops = &beep_ops;
#else
    device->init = drv_beep_init;
    device->open = drv_beep_open;
    device->close = drv_beep_close;
    device->write = drv_beep_write;
    device->control = drv_beep_control;
#endif
    device->user_data = RT_NULL;
    /* register beep device */
    result = rt_device_register(device, "beep", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
    if (result != RT_EOK)
    {
        LOG_E("beep register err code: %d", result);
        return result;
    }
    LOG_I("beep register success");

    return result;
}
INIT_DEVICE_EXPORT(drv_beep_hw_init);

//////////////////////////////////////////////////////////////////////////////////////////////////
#if DEMO   
// 参考示例代码
int my_test(void)
{
    rt_device_t dev = RT_NULL;
    struct beep_state beep_s;

    dev  = rt_device_find("beep"); 
    if (dev == RT_NULL)
    {
        rt_kprintf("beep device not found!\r\n");
        return -RT_ENOSYS;
    }
    rt_kprintf("beep device found!\r\n");

    dev->init(dev);
    dev->open(dev, RT_DEVICE_FLAG_RDWR);

    beep_s.on = 1;
    beep_s.hz = 1000;
    beep_s.time = 5000;
    dev->write(dev, 0, &beep_s, sizeof(beep_s));
}
#endif 